from redis import ConnectionPool, StrictRedis, connection
from typing import Optional, Union

from .typing import AbsExpiryT, ExpiryT


class BaseRedis:
    def __init__(self, app=None, config_prefix="REDIS"):
        self._client: Optional[StrictRedis] = None
        self.config_prefix = config_prefix

        if app is not None:
            self.init_app(app)

    def init_app(self, app):
        raise NotImplementedError(".init_app() must be overridden.")

    def __getattr__(self, name):
        return getattr(self._client, name)

    def get(self, key):
        return self._client.get(key)

    def set(self, name: str,
            value: str,
            ex: Union[ExpiryT, None] = None,
            px: Union[ExpiryT, None] = None,
            nx: bool = False,
            xx: bool = False,
            keepttl: bool = False,
            get: bool = False,
            exat: Union[AbsExpiryT, None] = None,
            pxat: Union[AbsExpiryT, None] = None):
        return self._client.set(
            name, value, ex, px, nx, xx, keepttl, get, exat, pxat
        )

    def expire(self,
               name: str,
               time: ExpiryT,
               nx: bool = False,
               xx: bool = False,
               gt: bool = False,
               lt: bool = False):
        self._client.expire(name, time, nx, xx, gt, lt)

    def persist(self, name: str):
        """设置key永不过期"""
        self._client.persist(name)


class FlaskOptionsMinix:
    config_prefix = "REDIS"

    def _get_redis_url(self, app):
        return app.config.get(
            "{0}_URL".format(self.config_prefix), "redis://localhost:6379/0"
        )

    def _get_pool_max_connections(self, app):
        return app.config.get(
            "{0}_MAX_CONNECTIONS".format(self.config_prefix), 10
        )


class RedisPool(BaseRedis, FlaskOptionsMinix):

    def init_app(self, app):
        max_connections = self._get_pool_max_connections(app)
        url = self._get_redis_url(app)
        pool = ConnectionPool.from_url(url)
        self._client = StrictRedis(connection_pool=pool, max_connections=max_connections)


class Redis(BaseRedis, FlaskOptionsMinix):
    def init_app(self, app):
        url = self._get_redis_url(app)
        url_options = connection.parse_url(url)
        self._client = StrictRedis(**url_options)
